/*********************************************************************************
 *      Copyright:  (C) 2022 Zhang Changxing<ZhangChangxingVIP@163.com>
 *                  All rights reserved.
 *
 *       Filename:  get_sms.c
 *    Description:  This file function to achieve the main text message access.
 *                 
 *        Version:  1.0.0(07/28/2022)
 *         Author:  Zhang Changxing <ZhangChangxingVIP@163.com>
 *      ChangeLog:  1, Release initial version on "07/28/2022  01:33:25 AM"
 *                 
 ********************************************************************************/


#include "get_sms.h"

/*--------------------------------------------------------------
 *   description:   Character stream byte stream
 *          args:   $source:    Character stream buffer address
 *                  $dest  :    Byte stream buffer address
 *                  $source_len:Character stream buffer length
 *  return value:   <0: failure,    =0:ok 
 *--------------------------------------------------------------*/
int str_to_hex(char *source, char *dest, int source_len)
{
    char    highbyte;//High byte
    char    lowbyte;//The low byte
    int     i = 0;

    //In the received message string, there are only numbers and letters, so only numbers and letters can be processed
    for (i; 2*i < source_len; i ++)
    {
        highbyte = toupper(source[i*2]);//Convert all lowercase letters to uppercase letters
        lowbyte = toupper(source[i*2 +1]);

        if(highbyte <= 0x39)
            highbyte -= 0x30;
        else
            highbyte -= 0x37;

        if(lowbyte <= 0x39)
            lowbyte -= 0x30;
        else
            lowbyte -= 0x37;

        dest[i] = (highbyte << 4) | lowbyte;
        //log_debug("dest[%d]=%02x\n",i, dest[i]);
    } 

    return 0;
}


/*--------------------------------------------------------------
 *   description:   Unicode encoding to UTF8 encoding
 *          args:   $unic_buf:    Unicode encoding buffer address
 *                  $unic_len:    Unicode encoding buffer length
 *                  $utf8_buf:    UTF8 Encoding buffer address
 *                  $utf8_len:    UTF8 Encoding buffer length
 *  return value:   <0: failure,    =0:ok 
 *--------------------------------------------------------------*/
int unicode_to_utf8(char *source, size_t source_len, char *dest, size_t dest_len)
{
    int     i = 0;
    char    temp;
    int     retval = -1;
    iconv_t cd;
    char    unicode_buf[512] = {0};
    

    if (!source)
    {
        log_error("[%s]Invalid argument!\n", __func__);
        return -1;
    }
    //log_debug("[%s]source:%s\n", __func__, source);

    str_to_hex(source, unicode_buf, strlen(source));

    for (i; i < sizeof(unicode_buf); i +=2)
    {
        temp = unicode_buf[i];
        unicode_buf[i] = unicode_buf[i+1];
        unicode_buf[i+1] = temp;
    }

    cd = iconv_open("UTF-8","UNICODE");
    if (cd < 0)
    {
        log_error("[%s]iconv_open() failure!\n", __func__);
        return -2;
    }

    char    *source_ptr = unicode_buf;
    

    retval =  iconv(cd, &source_ptr, &source_len, &dest, &dest_len);
    if(retval < 0)
    {
        log_error("[%s]Unicode to utf-8 failure:%s\n", __func__, strerror(errno));
        iconv_close(cd);
        return -3;
    }

    //log_debug("Unicode to utf-8 successfully:%s\n", dest);

    iconv_close(cd);
    return 0;
}


/*--------------------------------------------------------------
 *   description:   Used for Text format decoding
 *          args:   $source:        Character stream buffer address
 *                  $dest:          Destination buffer address
 *                  $source_len:    Character stream length
 *  return value:   <0: failure,    =0:ok 
 *--------------------------------------------------------------*/
int text_decod(char *source, char *dest, int source_len)
{
    char temp_buf[512] = {0};

    if (!source|| !dest)
    {
        log_error("[%s]Invalid argument.\n", __func__);
        return -1;
    }

    str_to_hex(source, temp_buf, source_len);
    decode7bit(temp_buf, dest, strlen(temp_buf));

    return 0;
}


/*--------------------------------------------------------------
 *   description:   This parameter is used to calculate the PDU 
 *                  center number, source number, and data length
 *          args:   $ptr:        Character stream buffer address
 *  return value:   <0: failure,    =0:ok 
 *--------------------------------------------------------------*/
int calculate_len(char *ptr)
{
    int len;
    int highbyte;
    int lowbyte;

    if (*ptr < 0x39)
        highbyte = (*ptr - 0x30)*16;
    else
        highbyte = (*ptr-0x37)*16;

    //log_debug("highbyte:%d\n", highbyte);

    ptr++;
    if (*ptr < 0x39)
        lowbyte = *ptr - 0x30;
    else
        lowbyte = *ptr - 0x37;

    //log_debug("lowbyte:%d\n", lowbyte);
    len = highbyte + lowbyte;
    //log_debug("len:%d\n", len);

    return len;
}


/*--------------------------------------------------------------
 *   description:   Get information about a specified number
 *          args:   $ttyusb_ctx:    Serial port property context
 *                  $sms_buf:       The address of the buffer where 
 *                  the returned information is stored
 *                  $sms_buf_len:   sms_buf length
 *                  $target_number: Destination number buffer address
 *  return value:   <0: failure,    =0:ok 
 *--------------------------------------------------------------*/
int get_specified_sms(ttyusb_ctx_t *ttyusb_ctx, char *sms_buf, int sms_buf_len, char *target_number)
{
    int     retval = -1;
    char    temp_buf[1024] = {0};
    char    *start_ptr = NULL;
    int     center_number_len = 0;
    char    phone_number[32] = {0};
    int     phone_len = 0;
    int     phone_flag = 0;
    int     encoding = 0;//编码
    int     data_len = 0;
    char    send_buf[128] = {0};
    char    time_buf[13] = {0};
    int     index = 0;
    int     j = 0;
    char    temp;
    char    data_buf[1024] = {0};
    int     sms_flag = 1;

    if (!ttyusb_ctx)
    {
        log_error("[%s]Invalid argument!\n", __func__);
        return -1;
    }

    retval = send_at_cmd(ttyusb_ctx, "AT+CSDH=1\r", "OK", NULL, 0);
    if(retval < 0)
    {
        log_error("[%s]Send command AT+CSDH=1 failure!\n", __func__);
        return -2;
    }
    

    while (1)
    {
        memset(send_buf, 0 , sizeof(send_buf));
        sprintf(send_buf, "AT+CMGR=%d\r", index);
        memset(temp_buf, 0, sizeof(temp_buf));

        retval = send_at_cmd(ttyusb_ctx, send_buf, "OK", temp_buf, sizeof(temp_buf));
        if(retval < 0)
        {
            log_error("[%s]There is no message %d\n", __func__, index);
            return -3;
        }

        start_ptr = strstr(temp_buf, "+CMGR");
        if(NULL == start_ptr)
        {
            log_error("[%s]There is no message %d\n", __func__, index);
            break;
        }


        start_ptr = strstr(start_ptr, "\r\n");
        start_ptr += 2;//Let the pointer point to the front of the PDU
        center_number_len = calculate_len(start_ptr);//Calculate the length of the center number
        start_ptr = start_ptr + 2 + center_number_len*2 + 2;
        phone_len = calculate_len(start_ptr);//Calculate the length of the source number
        //If the number is an odd number of digits, add an F calculation
        if(phone_len%2 != 0)
        {
            phone_len++;
            phone_flag = 1;
        }

        //Get the sender number
        strncpy(phone_number, start_ptr+2+2, phone_len);
        for(j = 0; j < phone_len; j +=2)
        {
            temp = phone_number[j];
            phone_number[j] = phone_number[j+1];
            if(phone_flag && ((phone_len -2) == j))
            {
                phone_number[j+1] ='\0';
            }
            else
            {
                phone_number[j+1] = temp;
            }
        }

        if(strncmp(target_number, phone_number, strlen(phone_number)))
        {
            
            start_ptr = NULL;
            index++;
            continue;
        }

        printf("PDU package:%s\n", temp_buf);
        printf("SMS Index:%d\n", index);
        printf("Sender:%s\n", phone_number);


        //log_debug("target_number:%s\n", target_number);
        start_ptr = start_ptr + 2 + 2 + phone_len  + 2;
        encoding = calculate_len(start_ptr);//Get the encoding format
        start_ptr = start_ptr + 2 ; 
        snprintf(time_buf, 12+1, "%s", start_ptr);

        printf("Receive time:");
        for(j = 0; j < 12; j +=2)
        {
            temp = time_buf[j];
            time_buf[j] = time_buf[j+1];
            time_buf[j+1] = temp;
            printf("-%c%c", time_buf[j], time_buf[j+1]);
        }
        printf("\n");
        
        start_ptr = start_ptr + 12 + 2;
        data_len = calculate_len(start_ptr);
        data_len = data_len*2;
        start_ptr = start_ptr +2;
        memset(data_buf, 0, data_len);
        snprintf(data_buf, data_len+1, "%s", start_ptr);

        //log_debug("The data PDU is %s\n", data_buf);
        memset(sms_buf, 0, sms_buf_len);
        if(encoding)
        {
            retval = unicode_to_utf8(data_buf, sizeof(data_buf), sms_buf, sms_buf_len);
        }
        else
        {
            text_decod(start_ptr, sms_buf, data_len);
            
        }

        printf("SMS:%s\n", sms_buf);
        start_ptr = NULL;
        index++;
        
        printf("-----------------------------------------------------------------------------------------------------\n");
            
    }

}


/*--------------------------------------------------------------
 *   description:   Get information about a specified number
 *          args:   $ttyusb_ctx:    Serial port property context
 *                  $sms_buf:       The address of the buffer where 
 *                  the returned information is stored
 *                  $sms_buf_len:   sms_buf length
 *  return value:   <0: failure,    =0:ok 
 *--------------------------------------------------------------*/
int get_all_sms(ttyusb_ctx_t *ttyusb_ctx, char *sms_buf, int sms_buf_len)
{
    int     retval = -1;
    char    temp_buf[1024] = {0};
    char    *start_ptr = NULL;
    int     center_number_len = 0;
    char    phone_number[32] = {0};
    int     phone_len = 0;
    int     phone_flag = 0;
    int     encoding = 0;
    int     data_len = 0;
    char    send_buf[128] = {0};
    char    time_buf[13] = {0};
    int     index = 0;
    int     j = 0;
    char    temp;
    char    data_buf[1024] = {0};

    if (!ttyusb_ctx)
    {
        log_error("[%s]Invalid argument.\n", __func__);
        return -1;
    }

    retval = send_at_cmd(ttyusb_ctx, "AT+CSDH=1\r", "OK", NULL, 0);
    if(retval < 0)
    {
        log_error("[%s]Send command AT+CSDH=1 failure!\n", __func__);
        return -2;
    }


    while (1)
    { 
        memset(send_buf, 0 , sizeof(send_buf));
        sprintf(send_buf, "AT+CMGR=%d\r", index);
        memset(temp_buf, 0, sizeof(temp_buf));
        retval = send_at_cmd(ttyusb_ctx, send_buf, "+CMGR", temp_buf, sizeof(temp_buf));
        if(retval < 0)
        {
            printf("There is no index:%d\n", index);
            break;
            return -3;
        }
        start_ptr = strstr(temp_buf, "+CMGR");
        
        
        start_ptr = strstr(start_ptr, "\r\n");
        start_ptr += 2;//Let the pointer point to the front of the PDU
        center_number_len = calculate_len(start_ptr);//Calculate the length of the center number
        start_ptr = start_ptr + 2 + center_number_len*2 + 2;
        phone_len = calculate_len(start_ptr);//Calculate the length of the sender number

        //If the number is an odd number of digits, add an F calculation
        if(phone_len%2 != 0)
        {
            phone_len++;
            phone_flag = 1;
        }

        //Get the sender number
        strncpy(phone_number, start_ptr+2+2, phone_len);
        for(j = 0; j < phone_len; j +=2)
        {
            temp = phone_number[j];
            phone_number[j] = phone_number[j+1];
            if(phone_flag && ((phone_len -2) == j))
            {
                phone_number[j+1] ='\0';
            }
            else
            {
                phone_number[j+1] = temp;
            }
        }

        printf("PDU package:%s\n", temp_buf);
        printf("SMS Index:%d\n", index);
        printf("Sender:%s\n", phone_number);


        start_ptr = start_ptr + 2 + 2 + phone_len  + 2;
        encoding = calculate_len(start_ptr);//Get the encoding format
        start_ptr = start_ptr + 2 ;

        memset(time_buf, 0 ,sizeof(time_buf));
        snprintf(time_buf, 12+1, "%s", start_ptr);

        printf("Receive time:");
        for(j = 0; j < 12; j +=2)
        {
            temp = time_buf[j];
            time_buf[j] = time_buf[j+1];
            time_buf[j+1] = temp;
            printf("-%c%c", time_buf[j], time_buf[j+1]);
        }
        printf("\n");
        
        
        start_ptr = start_ptr + 12 + 2;
        
        data_len = calculate_len(start_ptr);
        data_len = data_len*2;
        start_ptr = start_ptr +2;
        memset(data_buf, 0, data_len);
        snprintf(data_buf, data_len+1, "%s", start_ptr);

        if(encoding)
        {
            memset(sms_buf, 0, sms_buf_len);
            retval = unicode_to_utf8(data_buf, sizeof(data_buf), sms_buf, sms_buf_len);
        }
        else
        {
            text_decod(start_ptr, sms_buf, data_len);
            
        }

        printf("SMS:%s\n", sms_buf);
        start_ptr = NULL;
        index++;

        printf("-----------------------------------------------------------------------------------------------------\n");
            
    }

}


/*--------------------------------------------------------------
 *   description:   Decoding by 7bit encoding
 *          args:   $source:    Source buffer address
 *                  $dest  :    The target buffer address
 *                  $source_len:Source buffer length
 *  return value:   <0: failure,    =0:ok 
 *--------------------------------------------------------------*/
int decode7bit(const unsigned char* source, char* dest, int source_len)
{
        int nsrc = 0;  
        int ndst = 0;
        int nbyte = 0;
        unsigned char nleft = 0;

        if (!source||!dest||(source_len<=0))
        {
            log_error("[%s]Invalid parameter\n",__func__);
            return -1;
        }
        
        while (nsrc < source_len)
        {
            *dest = ((*source << nbyte) | nleft) & 0x7f;
            nleft = *source >> (7-nbyte);
            dest++;
            ndst++;
            nbyte++;
            if(nbyte == 7)
            {
                *dest = nleft;
                dest++;
                ndst++;
                nbyte = 0;
                nleft = 0;
            }
            source++;
            nsrc++;
        }
        *dest = 0;

        return ndst;
}


/*--------------------------------------------------------------
 *   description:   Get information about a specified number
 *          args:   $ttyusb_ctx:    Serial port property context
 *                  $sms_buf:       The address of the buffer where 
 *                  $target_number: Destination number buffer address
 *  return value:   <0: failure,    =0:ok 
 *--------------------------------------------------------------*/
int delete_sms(ttyusb_ctx_t *ttyusb_ctx, char *target_number)
{
    int     retval = -1;
    char    temp_buf[1024] = {0};
    char    *start_ptr = NULL;
    int     center_number_len = 0;
    char    phone_number[32] = {0};
    int     phone_len = 0;
    int     phone_flag = 0;
    char    send_buf[128] = {0};
    char    time_buf[13] = {0};
    int     index = 0;
    int     j = 0;
    char    temp;
    char    data_buf[1024] = {0};
    int     sms_flag = 1;

    if (!ttyusb_ctx)
    {
        log_error("[%s]Invalid argument!\n", __func__);
        return -1;
    }

    retval = send_at_cmd(ttyusb_ctx, "AT+CSDH=1\r", "OK", NULL, 0);
    if(retval < 0)
    {
        log_error("[%s]Send command AT+CSDH=1 failure!\n", __func__);
        return -2;
    }
    

    while (1)
    {
        memset(send_buf, 0 , sizeof(send_buf));
        sprintf(send_buf, "AT+CMGR=%d\r", index);
        memset(temp_buf, 0, sizeof(temp_buf));

        retval = send_at_cmd(ttyusb_ctx, send_buf, "OK", temp_buf, sizeof(temp_buf));
        if(retval < 0)
        {
            log_error("[%s]There is no message %d\n", __func__, index);
            return -3;
        }

        start_ptr = strstr(temp_buf, "+CMGR");
        if(NULL == start_ptr)
        {
            log_error("[%s]There is no message %d\n", __func__, index);
            break;
        }

        start_ptr = strstr(start_ptr, "\r\n");
        start_ptr += 2;//Let the pointer point to the front of the PDU
        center_number_len = calculate_len(start_ptr);//Calculate the length of the center number
        start_ptr = start_ptr + 2 + center_number_len*2 + 2;
        phone_len = calculate_len(start_ptr);//Calculate the length of the sender number

        //If the number is an odd number of digits, add an F calculation
        if(phone_len%2 != 0)
        {
            phone_len++;
            phone_flag = 1;
        }

        //Get the sender number
        strncpy(phone_number, start_ptr+2+2, phone_len);
        for(j = 0; j < phone_len; j +=2)
        {
            temp = phone_number[j];
            phone_number[j] = phone_number[j+1];
            if(phone_flag && ((phone_len -2) == j))
            {
                phone_number[j+1] ='\0';
            }
            else
            {
                phone_number[j+1] = temp;
            }
        }

        if(strncmp(target_number, phone_number, strlen(phone_number)))
        {
            
            start_ptr = NULL;
            index++;
            continue;
        }

        memset(send_buf, 0 , sizeof(send_buf));
        sprintf(send_buf,"AT+CMGD=%d\r",index);
        retval = send_at_cmd(ttyusb_ctx, send_buf, "OK", NULL, 0);
        if(retval < 0)
        {
            log_error("[%s]Failed to delte the information\n", __func__);
            return -3;
        }
        printf("Delete message %d ok!\n",index);

        start_ptr = NULL;
        index++;
        
        printf("-----------------------------------------------------------------------------------------------------\n");
            
    }

}

